--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
vendor/rns_filesync/README.md dev (9051d6cc) Text, 6.75 KB
Tc9d1d9# RNS FileSync
Decentralized peer-to-peer file synchronization over the Reticulum Network Stack.
This package is designed as an embeddable library for host programs such as
MeshChatX and Sideband, with a thin CLI for standalone use. There is no TUI.
For usability and easy usage this follows rngit permissions and configuration.
Tc9d1d9## Features
Tff7b72- Peer-to-peer sync with no central server
Tff7b72- Delta sync for changed blocks
Tff7b72- Path-jailed writes and rngit-style ACL (permission:target)
Tff7b72- Embed-safe: reuses an existing RNS.Reticulum instance when present
Tff7b72- Works over any Reticulum medium (radio, LoRa, WiFi, internet)
Tff7b72- Daemon mode via --no-repl for init systems and containers
Tc9d1d9## Install
Over Reticulum with pip-rns (no internet required once you have a path):
Ta5d6ff```Ta5d6ffbash
pip-rns install rns://06a54b505bb67b25ef3f8097e8001edc/public/rns-filesync --pipx
Ta5d6ff```
From a release wheel over Reticulum (no source build):
Ta5d6ff```Ta5d6ffbash
pip-rns install --from-release rns://06a54b505bb67b25ef3f8097e8001edc/public/rns-filesync --ref v1.0.0 --pipx
Ta5d6ff```
From GitHub with pipx:
Ta5d6ff```Ta5d6ffbash
pipx install git+https://github.com/Quad4-Software/RNS-Filesync
Ta5d6ff```
From a local wheel:
Ta5d6ff```Ta5d6ffbash
make wheel
pipx install dist/rns_filesync-*.whl
T8b949e# or: pip install dist/rns_filesync-*.whl
Ta5d6ff```
From a local checkout (development):
Ta5d6ff```Ta5d6ffbash
pip install -e Ta5d6ff".[dev]"
T8b949e# or: make install-user
Ta5d6ff```
Requires rns>=1.4.1. Current package version: **1.0.0**.
Ta5d6ff```Ta5d6ffbash
rns-filesync -v
T8b949e# rns-filesync 1.0.0 | built 2026-07-19T12:00:00Z | commit abc1234
Ta5d6ff```
Tc9d1d9## Config
FileSync uses an rngit-like config directory (default Ta5d6ff`~/.rns_filesync/`):
Ta5d6ff```Ta5d6ffbash
rns-filesync -d ~/shared
T8b949e# creates ~/.rns_filesync/config on first run
Ta5d6ff```
| Flag | Meaning |
|------|---------|
| Ta5d6ff`--config DIR` | FileSync config directory (default Ta5d6ff`~/.rns_filesync`) |
| Ta5d6ff`--rnsconfig DIR` | Reticulum config directory (default Ta5d6ff`~/.reticulum`) |
| Ta5d6ff`-d DIR` | Sync directory (overrides Ta5d6ff`[filesync] directory`) |
Example Ta5d6ff`~/.rns_filesync/config`:
Ta5d6ff```Ta5d6ffini
Tff7b72[filesync]
Te6edf3announce_interval Tff7b72= Ta5d6ff300
T8b949e# directory = ~/shared
Te6edf3identity Tff7b72= Ta5d6ffrns_filesync
T8b949e# peers = 9710b86ba12c42d1d8f30f74fe509286
T8b949e# blocked_identities = d31aeea49873006f13b3415520666a4e
Tff7b72[aliases]
T8b949e# alice = d09285e660cfe27cee6d9a0beb58b7e0
Tff7b72[access]
T8b949e# sync = r:all, w:9710b86ba12c42d1d8f30f74fe509286, d:9710b86ba12c42d1d8f30f74fe509286
Tff7b72[logging]
Te6edf3loglevel Tff7b72= Ta5d6ff4
Ta5d6ff```
Identities are stored under Ta5d6ff`~/.rns_filesync/identities/`.
Tc9d1d9## Permissions
Same rule form as rngit: Ta5d6ff`permission:target`.
| Perm | Meaning |
|------|---------|
| Ta5d6ff`r` | read |
| Ta5d6ff`w` | write |
| Ta5d6ff`d` | delete |
| Ta5d6ff`rw` | read/write |
| Ta5d6ff`rwd` | read/write/delete |
| Ta5d6ff`adm` | admin (all) |
Targets: identity hash, alias, Ta5d6ff`all`, or Ta5d6ff`none`.
When any ACL rule is loaded, access is **deny by default**. With no rules configured, the peer stays open (library/embed default).
Sidecar Ta5d6ff`.allowed` files (first found wins alongside config Ta5d6ff`[access]`):
Tff7b72- Ta5d6ff`<sync_dir>.allowed`
Tff7b72- Ta5d6ff`<parent>/<name>.allowed`
Tff7b72- Ta5d6ff`<sync_dir>/.allowed`
See Ta5d6ff`permissions.example`.
Ta5d6ff```Ta5d6ffbash
rns-filesync -d ~/shared --allow r:all --allow w:9710b86ba12c42d1d8f30f74fe509286
Ta5d6ff```
Tc9d1d9## CLI
Ta5d6ff```Ta5d6ffbash
rns-filesync -d ~/shared
rns-filesync -d ~/shared -p <peer_identity_hash>
rns-filesync --config ~/.rns_filesync --rnsconfig ~/.reticulum -d ~/shared
rns-filesync -v
rns-filesync --version
Ta5d6ff```
Ta5d6ff`-v` / Ta5d6ff`--version` prints version, bake build date, and git commit when available.
Ta5d6ff`-p` expects a peer **identity hash**. A destination hash is accepted as fallback
after the peer has announced.
Interactive commands: Ta5d6ff`status`, Ta5d6ff`peers`, Ta5d6ff`files`, Ta5d6ff`connect`, Ta5d6ff`disconnect`,
Ta5d6ff`browse`, Ta5d6ff`download`, Ta5d6ff`announce`, Ta5d6ff`quit`.
Logging verbosity uses Ta5d6ff`--verbose` (repeatable). Quiet mode is Ta5d6ff`-q`.
Tc9d1d9## Man page
Ta5d6ff```Ta5d6ffbash
make install-user T8b949e# installs man page to ~/.local/share/man/man1/
man rns-filesync
Ta5d6ff```
Tc9d1d9## Library embed (MeshChatX-style)
Ta5d6ff```Ta5d6ffpython
Tff7b72from T7ee787rns_filesync Tff7b72import Te6edf3FileSyncService
Tff7b72from T7ee787rns_filesyncT7ee787.T7ee787permissions Tff7b72import Te6edf3PermissionStore
Te6edf3perms Tff7b72= Te6edf3PermissionStoreTb4b4b4(Tb4b4b4)
Te6edf3permsTff7b72.Td2a8ffadd_ruleTb4b4b4(Ta5d6ff"Ta5d6ffr:allTa5d6ff"Tb4b4b4)
Te6edf3permsTff7b72.Td2a8ffadd_ruleTb4b4b4(Ta5d6ff"Ta5d6ffw:9710b86ba12c42d1d8f30f74fe509286Ta5d6ff"Tb4b4b4)
Te6edf3service Tff7b72= Te6edf3FileSyncServiceTb4b4b4(
Te6edf3identityTff7b72=Te6edf3host_identityTb4b4b4,
Te6edf3sync_directoryTff7b72=Ta5d6ff"Ta5d6ff/path/to/syncTa5d6ff"Tb4b4b4,
Te6edf3reticulumTff7b72=Te6edf3existing_reticulumTb4b4b4,
Te6edf3permissionsTff7b72=Te6edf3permsTb4b4b4,
Tb4b4b4)
Te6edf3dest_hash Tff7b72= Te6edf3serviceTff7b72.Td2a8ffstartTb4b4b4(Te6edf3monitorTff7b72=Tff7b72TrueTb4b4b4)
Te6edf3serviceTff7b72.Td2a8ffconnect_peerTb4b4b4(Te6edf3peer_identity_hashTb4b4b4)
Te6edf3serviceTff7b72.Td2a8ffstopTb4b4b4(Tb4b4b4)
Ta5d6ff```
Keep aspect Ta5d6ff`rns_filesync.filesync` for wire compatibility.
Tc9d1d9## Sideband plugin
Install Ta5d6ff`rns-filesync` into the same Python environment Sideband uses, then copy
the drop-in plugins from Ta5d6ff`sideband/` into Sideband's plugins directory and
enable service/command plugins in Sideband settings.
Ta5d6ff```Ta5d6ffbash
T8b949e# After installing rns-filesync (pip / pipx / pip-rns):
cp sideband/rns_filesync_service.py ~/.config/sideband/plugins/
cp sideband/rns_filesync_command.py ~/.config/sideband/plugins/
Ta5d6ff```
Set Sideband's plugin path to that directory, enable **service plugins** and
**command plugins**, then restart Sideband.
The service plugin reuses Sideband's identity and Reticulum instance. Sync
directory, peers, and ACL come from Ta5d6ff`~/.rns_filesync/config`. If no directory
is set there, it defaults to Ta5d6ff`~/.config/sideband/filesync`.
Remote LXMF commands (from a peer allowed to run Sideband commands):
Ta5d6ff```Ta5d6fftext
filesync status
filesync peers
filesync files
filesync announce
filesync connect <identity_hash>
filesync disconnect <peer_id>
Ta5d6ff```
Tc9d1d9## Daemon and packaging
Init units (non-root) live under packaging/ for systemd (system and user),
OpenRC, dinit, and runit. See packaging/README.md.
Ta5d6ff```Ta5d6ffbash
T8b949e# system (dedicated rns-filesync user, hardened)
sudo systemctl Tffa657enable --now rns-filesync
T8b949e# or per-user
systemctl --user Tffa657enable --now rns-filesync
Ta5d6ff```
Daemon entrypoint:
Ta5d6ff```Ta5d6ffbash
rns-filesync -d ~/shared --no-repl -q
Ta5d6ff```
Bubblewrap sandbox example (full command in packaging/README.md):
Ta5d6ff```Ta5d6ffbash
Te6edf3DATATff7b72=Ta5d6ff"Tffd700${Te6edf3XDG_DATA_HOMETff7b72:-Te6edf3$HOMETb4b4b4/.local/shareTffd700}Ta5d6ff/rns-filesync-sandboxTa5d6ff"
mkdir -p Ta5d6ff"Te6edf3$DATATa5d6ff/configTa5d6ff" Ta5d6ff"Te6edf3$DATATa5d6ff/syncTa5d6ff" Ta5d6ff"Te6edf3$DATATa5d6ff/reticulumTa5d6ff"
Tffa657exec bwrap Tffea00\
--die-with-parent Tffea00\
--new-session Tffea00\
--proc /proc Tffea00\
--dev /dev Tffea00\
--ro-bind / / Tffea00\
--tmpfs /tmp Tffea00\
--bind Ta5d6ff"Te6edf3$DATATa5d6ff" Ta5d6ff"Te6edf3$DATATa5d6ff" Tffea00\
--uid Ta5d6ff"Tff7b72$(id -uTff7b72)Ta5d6ff" --gid Ta5d6ff"Tff7b72$(id -gTff7b72)Ta5d6ff" Tffea00\
rns-filesync Tffea00\
--config Ta5d6ff"Te6edf3$DATATa5d6ff/configTa5d6ff" Tffea00\
--rnsconfig Ta5d6ff"Te6edf3$DATATa5d6ff/reticulumTa5d6ff" Tffea00\
-d Ta5d6ff"Te6edf3$DATATa5d6ff/syncTa5d6ff" Tffea00\
--no-repl Tffea00\
-q
Ta5d6ff```
Tc9d1d9## Docker
Rootless multi-stage image and wheel builder under docker/. See docker/README.md.
Ta5d6ff```Ta5d6ffbash
docker build -f docker/Dockerfile -t rns-filesync:1.0.0 .
Ta5d6ff```
Tc9d1d9## Tests
Ta5d6ff```Ta5d6ffbash
make Tffa657test
pytest -m Ta5d6ff"not live and not exploratory"
pytest -m e2e
pytest -m live
Ta5d6ff```
Markers: Ta5d6ff`unit`, Ta5d6ff`acceptance`, Ta5d6ff`smoke`, Ta5d6ff`e2e`, Ta5d6ff`fuzz`, Ta5d6ff`live`, Ta5d6ff`exploratory`.
Useful Make targets (aligned with pip-rns): Ta5d6ff`meta`, Ta5d6ff`wheel`, Ta5d6ff`sdist`, Ta5d6ff`test`,
Ta5d6ff`install-user`, Ta5d6ff`man`, Ta5d6ff`sign`, Ta5d6ff`release-rns`, Ta5d6ff`clean`, Ta5d6ff`test-services`.
Tc9d1d9## License
BSD-2-Clause. See LICENSE.
──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────